/* arith.c */

#include "ptpd.h"

void scaledNanosecondsToInternalTime(const int64_t *scaledNanoseconds, TimeInternal *internal)
{
	int sign;
	int64_t nanoseconds = *scaledNanoseconds;

	/* Determine sign of result big integer number */
	if (nanoseconds < 0)
	{
		nanoseconds = -nanoseconds;
		sign = -1;
	}
	else
	{
		sign = 1;
	}

	/* fractional nanoseconds are excluded (see 5.3.2) */
	nanoseconds >>= 16;
	internal->seconds = sign * (nanoseconds / 1000000000);
	internal->nanoseconds = sign * (nanoseconds % 1000000000);
}

void fromInternalTime(const TimeInternal *internal, Timestamp *external)
{
	/* fromInternalTime is only used to convert time given by the system to a timestamp
	 * As a consequence, no negative value can normally be found in (internal)
	 * Note that offsets are also represented with TimeInternal structure, and can be negative,
	 * but offset are never convert into Timestamp so there is no problem here.*/
	if ((internal->seconds & ~INT_MAX) || (internal->nanoseconds & ~INT_MAX))
	{
		DBG("Negative value canno't be converted into timestamp \n");
		return;
	}
	else
	{
		external->secondsField.lsb = internal->seconds;
		external->nanosecondsField = internal->nanoseconds;
		external->secondsField.msb = 0;
	}
}

void toInternalTime(TimeInternal *internal, const Timestamp *external)
{
	/* Program will not run after 2038... */
	if (external->secondsField.lsb < INT_MAX)
	{
		internal->seconds = external->secondsField.lsb;
		internal->nanoseconds = external->nanosecondsField;
	}
	else
	{
		DBG("Clock servo canno't be executed : seconds field is higher than signed integer (32bits)\n");
		return;
	}
}

void normalizeTime(TimeInternal *r)
{
	r->seconds += r->nanoseconds / 1000000000;
	r->nanoseconds -= r->nanoseconds / 1000000000 * 1000000000;

	if (r->seconds > 0 && r->nanoseconds < 0)
	{
		r->seconds -= 1;
		r->nanoseconds += 1000000000;
	}
	else if (r->seconds < 0 && r->nanoseconds > 0)
	{
		r->seconds += 1;
		r->nanoseconds -= 1000000000;
	}
}

void addTime(TimeInternal *r, const TimeInternal *x, const TimeInternal *y)
{
	r->seconds = x->seconds + y->seconds;
	r->nanoseconds = x->nanoseconds + y->nanoseconds;

	normalizeTime(r);
}

void subTime(TimeInternal *r, const TimeInternal *x, const TimeInternal *y)
{
	r->seconds = x->seconds - y->seconds;
	r->nanoseconds = x->nanoseconds - y->nanoseconds;

	normalizeTime(r);
}

void div2Time(TimeInternal *r)
{
	r->nanoseconds += r->seconds % 2 * 1000000000;
	r->seconds /= 2;
	r->nanoseconds /= 2;

	normalizeTime(r);
}

int32_t floorLog2(uint32_t n)
{
	int pos = 0;

	if (n == 0)
		return -1;

	if (n >= 1<<16) { n >>= 16; pos += 16; }
	if (n >= 1<< 8) { n >>=  8; pos +=  8; }
	if (n >= 1<< 4) { n >>=  4; pos +=  4; }
	if (n >= 1<< 2) { n >>=  2; pos +=  2; }
	if (n >= 1<< 1) {           pos +=  1; }
	return pos;
}
